package com.newcoder.service.impl;

import com.newcoder.entity.Comment;
import com.newcoder.entity.DiscussPost;
import com.newcoder.entity.Event;
import com.newcoder.entity.User;
import com.newcoder.event.EventProducer;
import com.newcoder.mapper.CommentMapper;
import com.newcoder.mapper.DiscussPostMapper;
import com.newcoder.mapper.UserMapper;
import com.newcoder.service.DiscussPostService;
import com.newcoder.util.HostHolder;
import com.newcoder.util.RedisKeyUtil;
import com.newcoder.util.ResponseWrapper;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Isolation;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.util.HtmlUtils;

import java.util.*;

import static com.newcoder.util.CommunityConstant.*;

/**
 * <p>
 *  服务实现类
 * </p>
 *
 * @author yjh
 * @since 2024-12-04 10:03:26
 */
@Service
public class DiscussPostServiceImpl implements DiscussPostService{

    private static final Logger logger = LoggerFactory.getLogger(DiscussPostServiceImpl.class);

    @Autowired
    private DiscussPostMapper discussPostMapper;

    @Autowired
    private UserMapper userMapper;

    @Autowired
    private CommentMapper commentMapper;

    @Autowired
    private HostHolder hostHolder;

    @Autowired
    private LikeServiceImpl likeService;

    @Autowired
    private EventProducer eventProducer;

    @Autowired
    private RedisTemplate redisTemplate;

    /**
     * 事务管理
     * isolation
     *  - Isolation.DEFAULT：使用底层数据库默认的隔离级别。
     *  - Isolation.READ_UNCOMMITTED：读取未提交数据：1，2，3，4，5
     *  - Isolation.READ_COMMITTED：读取已提交数据：3，4，5
     *  - Isolation.REPEATABLE_READ：可重复读：5
     *  - Isolation.SERIALIZABLE：串行化：null
     *
     * propagation
     *  - Propagation.REQUIRED: 支持当前事务(外部事务),如果不存在则创建新事务.
     *  - Propagation.REQUIRES_NEW: 创建一个新事务,并且暂停当前事务(外部事务).
     *  - Propagation.NESTED: 如果当前存在事务(外部事务),则嵌套在该事务中执行(独立的提交和回滚),否则就会REQUIRED一样.(以上三个常用)
     *
     *  - Propagation.SUPPORTS
     * 	- Propagation.MANDATORY
     *  - Propagation.NOT_SUPPORTED
     *  - Propagation.NEVER
     *
     * */
    @Override
    @Transactional(isolation = Isolation.READ_COMMITTED, propagation = Propagation.REQUIRED)
    public ResponseWrapper insertDiscussPost(DiscussPost discussPost) {
        if(discussPost == null){
            return ResponseWrapper.parameterError("参数不能为空");
        }

        User user = userMapper.selectById(discussPost.getUserId());
        if(user == null){
            return ResponseWrapper.markCustom(false, 500, "用户不存在");
        }

        if(discussPost.getTitle() == null){
            return ResponseWrapper.parameterError("标题不能为空");
        }
        if(discussPost.getContent() == null){
            return ResponseWrapper.parameterError("内容不能为空");
        }

        // 转义HTML标记
        discussPost.setTitle(HtmlUtils.htmlEscape(discussPost.getTitle()));
        discussPost.setContent(HtmlUtils.htmlEscape(discussPost.getContent()));
        // 过滤敏感词

        discussPost.setCreateTime(new Date());
        discussPost.setStatus(0);
        discussPost.setType(user.getType());
        discussPost.setCommentCount(0);
        discussPost.setScore(0.0);

        int i = discussPostMapper.insertDiscussPost(discussPost);
        if(i != 1){
            return ResponseWrapper.markCustom(false, 500, "新增失败");
        }

        // 触发发帖事件
        Event event = new Event()
                .setTopic(TOPIC_PUBLISH)
                .setUserId(user.getId())
                .setEntityType(ENTITY_TYPE_POST)
                .setEntityId(discussPost.getId());
        eventProducer.fireEvent(event);

        // 计算帖子分数
        String redisKey = RedisKeyUtil.getPostScoreKey();
        redisTemplate.opsForSet().add(redisKey, discussPost.getId());

        // 报错的情况,将来统一处理.
        return ResponseWrapper.markCustom(true, 200, "新增成功");
    }

    @Override
    public ResponseWrapper deleteDiscussPostById(Integer id) {
        if(id == null){
            return ResponseWrapper.parameterError("id不能为空");
        }

        int i = discussPostMapper.updateStatus(id, 2);
        if(i != 1){
            return ResponseWrapper.markCustom(false, 500, "删除失败");
        }
        // 触发删帖事件
        Event event = new Event()
                .setTopic(TOPIC_DELETE)
                .setUserId(hostHolder.getUser().getId())
                .setEntityType(ENTITY_TYPE_POST)
                .setEntityId(id);
        eventProducer.fireEvent(event);
        return ResponseWrapper.markCustom(true, 200, "删除成功");
    }

    @Override
    public ResponseWrapper updateDiscussPost(DiscussPost discussPost) {
        if(discussPost == null){
            return ResponseWrapper.parameterError("参数不能为空");
        }

        int i = discussPostMapper.updateDiscussPost(discussPost);
        if(i != 1){
            return ResponseWrapper.markCustom(false, 500, "修改失败");
        }
        return ResponseWrapper.markCustom(true, 200, "修改成功");
    }

    @Override
    public ResponseWrapper updateCommentCount(Integer id, Integer commentCount) {
        if(id == null || commentCount == null){
            return ResponseWrapper.parameterError("参数不能为空");
        }

        int i = discussPostMapper.updateCommentCount(id, commentCount);
        if(i != 1){
            return ResponseWrapper.markCustom(false, 500, "修改失败");
        }
        return ResponseWrapper.markCustom(true, 200, "修改成功");
    }

    @Override
    public ResponseWrapper updateType(Integer id, Integer type) {
        if(id == null || type == null){
            return ResponseWrapper.parameterError("参数不能为空");
        }

        int i = discussPostMapper.updateType(id, type);
        if(i != 1){
            return ResponseWrapper.markCustom(false, 500, "修改失败");
        }
        return ResponseWrapper.markCustom(true, 200, "修改成功");
    }

    @Override
    public ResponseWrapper updateStatus(Integer id, Integer status) {
        if(id == null || status == null){
            return ResponseWrapper.parameterError("参数不能为空");
        }

        int i = discussPostMapper.updateStatus(id, status);
        if(i != 1){
            return ResponseWrapper.markCustom(false, 500, "修改失败");
        }
        return ResponseWrapper.markCustom(true, 200, "修改成功");
    }

    @Override
    public ResponseWrapper updateScore(Integer id, double score) {
        if(id == null){
            return ResponseWrapper.parameterError("参数不能为空");
        }

        int i = discussPostMapper.updateScore(id, score);
        if(i != 1){
            return ResponseWrapper.markCustom(false, 500, "修改失败");
        }
        return ResponseWrapper.markCustom(true, 200, "修改成功");
    }

    @Override
    public ResponseWrapper selectDiscussPostById(Integer id) {
        if(id == null){
            return ResponseWrapper.parameterError("参数不能为空");
        }

        DiscussPost discussPost = discussPostMapper.selectDiscussPostById(id);
        if(discussPost == null){
            return ResponseWrapper.markCustom(false, 500, "查找失败");
        }
        ResponseWrapper wrapper = ResponseWrapper.markCustom(true, 200, "查找成功");
        wrapper.getData().put("discussPost", discussPost);
        return wrapper;
    }

    @Override
    public ResponseWrapper selectDiscussPostsPage(Integer status, Integer type, Integer currentPage, Integer pageSize) {
        //当前页第一个数据下标offset
        Integer currentNum = (currentPage - 1) * pageSize;
        //所有数据的数量
        Integer total = discussPostMapper.selectDiscussPostsTotal(status, type);
        //当前页数据
        List<DiscussPost> list = discussPostMapper.selectDiscussPostsPage(status, type, currentNum, pageSize);

        Integer pages = total%pageSize==0 ? total/pageSize : total/pageSize+1;
        ResponseWrapper wrapper = ResponseWrapper.markSuccess();
        wrapper.getData().put("discussPostList",list);                     //当前页数据
        wrapper.getData().put("total", total);                  //总数据个数
        wrapper.getData().put("currentPage", currentPage);      //当前页
        wrapper.getData().put("currentNum", currentNum);        //当前页第一个数据下标
        wrapper.getData().put("pageSize", pageSize);            //页大小
        wrapper.getData().put("pages", pages);                  //总页数
        return wrapper;
    }

    //查看谈论页详情
    @Override
    public ResponseWrapper getDiscussPost(Integer discussPostId){
        // 帖子
        DiscussPost post = discussPostMapper.selectDiscussPostById(discussPostId);

        // 作者
        User user = userMapper.selectById(post.getUserId());

        // 点赞数量
        long likeCount = likeService.findEntityLikeCount(ENTITY_TYPE_POST, discussPostId);

        // 点赞状态
        int likeStatus = hostHolder.getUser() == null ? 0 : likeService.findEntityLikeStatus(hostHolder.getUser().getId(), ENTITY_TYPE_POST, discussPostId);

        // 评论: 给帖子的评论
        // 回复: 给评论的评论
        // 评论列表
        List<Comment> commentList = commentMapper.selectCommentsPage(
                ENTITY_TYPE_POST, post.getId(), 0, Integer.MAX_VALUE); //懒加载
        // 评论VO列表
        List<Map<String, Object>> commentVoList = new ArrayList<>();
        if (commentList != null) {
            for (Comment comment : commentList) {
                // 评论VO
                Map<String, Object> commentVo = new HashMap<>();
                // 评论
                commentVo.put("comment", comment);
                // 作者
                commentVo.put("user", userMapper.selectById(comment.getUserId()));
                // 点赞数量
                likeCount = likeService.findEntityLikeCount(ENTITY_TYPE_COMMENT, comment.getId());
                commentVo.put("likeCount", likeCount);
                // 点赞状态
                likeStatus = hostHolder.getUser() == null ? 0 :
                        likeService.findEntityLikeStatus(hostHolder.getUser().getId(), ENTITY_TYPE_COMMENT, comment.getId());
                commentVo.put("likeStatus", likeStatus);

                // 回复列表
                List<Comment> replyList = commentMapper.selectCommentsPage(
                        ENTITY_TYPE_COMMENT, comment.getId(), 0, Integer.MAX_VALUE); //懒加载
                // 回复VO列表
                List<Map<String, Object>> replyVoList = new ArrayList<>();
                if (replyList != null) {
                    for (Comment reply : replyList) {
                        Map<String, Object> replyVo = new HashMap<>();
                        // 回复
                        replyVo.put("reply", reply);
                        // 作者
                        replyVo.put("user", userMapper.selectById(reply.getUserId()));
                        // 回复目标
                        User target = reply.getTargetId() == 0 ? null : userMapper.selectById(reply.getTargetId());
                        replyVo.put("target", target);
                        // 点赞数量
                        likeCount = likeService.findEntityLikeCount(ENTITY_TYPE_COMMENT, reply.getId());
                        replyVo.put("likeCount", likeCount);
                        // 点赞状态
                        likeStatus = hostHolder.getUser() == null ? 0 :
                                likeService.findEntityLikeStatus(hostHolder.getUser().getId(), ENTITY_TYPE_COMMENT, reply.getId());
                        replyVo.put("likeStatus", likeStatus);

                        replyVoList.add(replyVo);
                    }
                }
                commentVo.put("replys", replyVoList);

                // 回复数量
                int replyCount = commentMapper.selectCommentTotal(ENTITY_TYPE_COMMENT, comment.getId());
                commentVo.put("replyCount", replyCount);

                commentVoList.add(commentVo);
            }
        }

        ResponseWrapper wrapper = ResponseWrapper.markSuccess();
        wrapper.getData().put("post", post);
        wrapper.getData().put("user", user);
        wrapper.getData().put("likeCount", likeCount);
        wrapper.getData().put("likeStatus", likeStatus);
        wrapper.getData().put("comments", commentVoList);
        return wrapper;
    }

    //置顶
    @Override
    public ResponseWrapper setTop(Integer id) {
        int i = discussPostMapper.updateType(id, 1);
        if(i != 1){
            return ResponseWrapper.markCustom(false, 500, "修改失败");
        }

        // 触发发帖事件
        Event event = new Event()
                .setTopic(TOPIC_PUBLISH)
                .setUserId(hostHolder.getUser().getId())
                .setEntityType(ENTITY_TYPE_POST)
                .setEntityId(id);
        eventProducer.fireEvent(event);

        return ResponseWrapper.markCustom(true, 200, "置顶成功");
    }

    // 设置为精选
    @Override
    public ResponseWrapper setWonderful(Integer id) {
        int i = discussPostMapper.updateStatus(id, 1);

        if(i != 1){
            return ResponseWrapper.markCustom(false, 500, "修改失败");
        }

        // 触发发帖事件
        Event event = new Event()
                .setTopic(TOPIC_PUBLISH)
                .setUserId(hostHolder.getUser().getId())
                .setEntityType(ENTITY_TYPE_POST)
                .setEntityId(id);
        eventProducer.fireEvent(event);

        // 计算帖子分数
        String redisKey = RedisKeyUtil.getPostScoreKey();
        redisTemplate.opsForSet().add(redisKey, id);

        return ResponseWrapper.markCustom(true, 200, "修改成功");
    }
}
